﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sunboxsoft.ASMS.Client.Domain.Calculation
{
    public static class SettlementBillCalculation
    {
        /// <summary>
        /// 计算金额
        /// </summary>
        /// <param name="serviceItemArray"></param>
        /// <param name="materialArray"></param>
        /// <param name="payItemArray"></param>
        /// <param name="packageItemArray"></param>
        /// <param name="couponArray"></param>
        /// <param name="spendBalance"></param>
        /// <param name="multLineDetail">多行显示</param>
        /// <param name="detail"></param>
        /// <returns></returns>
        public static decimal Calc(WebRef.ESettlementBillServiceItem[] serviceItemArray,
            WebRef.ESettlementBillMaterial[] materialArray,
            WebRef.ESettlementBillPayItem[] payItemArray,
            WebRef.ESettlementBillPackageItem[] packageItemArray,
            WebRef.ESettlementBillCoupon[] couponArray,
            decimal spendBalance,
            bool multLineDetail,
            out string detail)
        {
            decimal amount = 0.0M;
            StringBuilder detailBuilder = new StringBuilder();

            decimal segmentOriginalAmount = 0.0M;
            decimal segmentAcutalAmount = 0.0M;

            if (packageItemArray != null && packageItemArray.Length > 0)
            {
                #region 有套餐
                if (serviceItemArray != null)
                {
                    // 被套餐减去的服务项目数量
                    int reduceCount = 0;
                    // 被套餐减去的服务项目金额
                    decimal reduceAmount = 0.0M;
                    // 需要付费的服务项目数量
                    int payCount = 0;
                    // 代金券金额
                    decimal voucherAmount = 0.0M;
                    // 代金券数量
                    int voucherCount = 0;
                    #region
                    // 处理优惠券
                    for (int packageItenIndex = 0; packageItenIndex < packageItemArray.Length; packageItenIndex++)
                    {
                        WebRef.ESettlementBillPackageItem packageItem = packageItemArray[packageItenIndex];
                        if (packageItem.PackageItemType == Constant.PackageItemTypes.Voucher)
                        {
                            voucherCount++;
                            voucherAmount += packageItem.PackageItemValue;
                        }
                    }

                    // 处理服务项的抵消
                    for (int serviceItemIndex = 0; serviceItemIndex < serviceItemArray.Length; serviceItemIndex++)
                    {
                        bool isReduce = false;
                        for (int packageItenIndex = 0; packageItenIndex < packageItemArray.Length; packageItenIndex++)
                        {
                            WebRef.ESettlementBillPackageItem packageItem = packageItemArray[packageItenIndex];

                            if (packageItem.PackageItemType == Constant.PackageItemTypes.ServiceItem)
                            {
                                Guid serviceItemId = new Guid(packageItem.PackageItemTagData);
                                if (serviceItemId == serviceItemArray[serviceItemIndex].ServiceItemId)
                                {
                                    reduceCount++;
                                    reduceAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour * serviceItemArray[serviceItemIndex].Discount;
                                    segmentOriginalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour;
                                    segmentAcutalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour * serviceItemArray[serviceItemIndex].Discount;
                                    isReduce = true;
                                    break;
                                }
                            }
                        }
                        if (!isReduce)
                        {
                            payCount++;
                            segmentOriginalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour;
                            segmentAcutalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour * serviceItemArray[serviceItemIndex].Discount;
                        }
                    }
                    #endregion
                    amount += segmentAcutalAmount;
                    amount -= voucherAmount;
                    amount -= reduceAmount;
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, payCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐项目)", reduceAmount, reduceCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐代金券)", voucherAmount, voucherCount);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, payCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐项目)", reduceAmount, reduceCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐代金券)", voucherAmount, voucherCount);
                    }
                }
                else
                {
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, 0);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, 0);
                    }
                }
                #endregion
            }
            else
            {
                #region 无套餐
                if (serviceItemArray != null)
                {
                    for (int index = 0; index < serviceItemArray.Length; index++)
                    {
                        segmentOriginalAmount += serviceItemArray[index].Price * serviceItemArray[index].Hour;
                        segmentAcutalAmount += serviceItemArray[index].Price * serviceItemArray[index].Hour * serviceItemArray[index].Discount;
                    }
                    amount += segmentAcutalAmount;
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, serviceItemArray.Length);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, serviceItemArray.Length);
                    }
                }
                else
                {
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}(0服务项目)", segmentAcutalAmount);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}(0服务项目)", segmentAcutalAmount);
                    }
                }
                #endregion
            }

            segmentOriginalAmount = 0.0M;
            segmentAcutalAmount = 0.0M;
            if (materialArray != null && materialArray.Length > 0)
            {
                for (int index = 0; index < materialArray.Length; index++)
                {
                    segmentOriginalAmount += materialArray[index].Price * materialArray[index].Count;
                    segmentAcutalAmount += materialArray[index].Price * materialArray[index].Count * materialArray[index].Discount;
                }
                amount += segmentAcutalAmount;
                if (multLineDetail)
                {
                    detailBuilder.Append("商品物料:");
                    detailBuilder.AppendFormat("+{0:N2}({1}商品)", segmentAcutalAmount, materialArray.Length);
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}({1}商品)", segmentAcutalAmount, materialArray.Length);
                }
            }
            else
            {
                if (multLineDetail)
                {
                    detailBuilder.Append("商品物料:");
                    detailBuilder.AppendFormat("+{0:N2}(0商品)", segmentAcutalAmount);
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}(0商品)", segmentAcutalAmount);
                }
            }

            decimal discountAmount = 0.0M;
            int discountCount = 0;
            decimal paymentAmount = 0.0M;
            int paymentCount = 0;
            if (payItemArray != null && payItemArray.Length > 0)
            {
                for (int index = 0; index < payItemArray.Length; index++)
                {
                    if (payItemArray[index].Type == Domain.Constant.PayItemTypes.Discount)
                    {
                        discountAmount += payItemArray[index].Amount;
                        discountCount++;
                    }
                    else
                    {
                        paymentAmount += payItemArray[index].Amount;
                        paymentCount++;
                    }
                }
                amount -= discountAmount;
                amount += paymentAmount;
                if (multLineDetail)
                {
                    detailBuilder.Append("其他项目:");
                    detailBuilder.AppendFormat("+{0:N2}({1}付费项)", paymentAmount, paymentCount);
                    detailBuilder.AppendFormat("-{0:N2}({1}优惠项)", discountAmount, discountCount);
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}({1}付费项)", paymentAmount, paymentCount);
                    detailBuilder.AppendFormat("-{0:N2}({1}优惠项)", discountAmount, discountCount);
                }
            }
            else
            {
                if (multLineDetail)
                {
                    detailBuilder.Append("其他项目:");
                    detailBuilder.AppendFormat("+{0:N2}(0付费项)", paymentAmount);
                    detailBuilder.AppendFormat("-{0:N2}(0优惠项)", discountAmount);

                    if (spendBalance > 0)
                    {
                        amount -= spendBalance;
                        detailBuilder.AppendFormat("-{0:N2}(余额)", spendBalance);
                    }
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}(0付费项)", paymentAmount);
                    detailBuilder.AppendFormat("-{0:N2}(0优惠项)", discountAmount);

                    if (spendBalance > 0)
                    {
                        amount -= spendBalance;
                        detailBuilder.AppendFormat("-{0:N2}(余额)", spendBalance);
                    }
                }
            }
            if (multLineDetail)
            {
                detailBuilder.AppendLine("----------------------------------------");
            }

            if (amount < 0)
            {
                amount = 0;
            }
            detail = detailBuilder.ToString();
            return amount;
        }

        /// <summary>
        /// 计算金额
        /// </summary>
        /// <param name="serviceItemArray"></param>
        /// <param name="materialArray"></param>
        /// <param name="payItemArray"></param>
        /// <param name="packageItemArray"></param>
        /// <param name="couponArray"></param>
        /// <param name="spendBalance"></param>
        /// <param name="multLineDetail">多行显示</param>
        /// <param name="detail"></param>
        /// <returns></returns>
        public static decimal Calc(WebRef.VSettlementBillServiceItem[] serviceItemArray,
            WebRef.VSettlementBillMaterial[] materialArray,
            WebRef.VSettlementBillPayItem[] payItemArray,
            WebRef.VSettlementBillPackageItem[] packageItemArray,
            WebRef.ESettlementBillCoupon[] couponArray,
            decimal spendBalance,
            bool multLineDetail,
            out string detail)
        {
            decimal amount = 0.0M;
            StringBuilder detailBuilder = new StringBuilder();

            decimal segmentOriginalAmount = 0.0M;
            decimal segmentAcutalAmount = 0.0M;

            if (packageItemArray != null && packageItemArray.Length > 0)
            {
                #region 有套餐
                if (serviceItemArray != null)
                {
                    // 被套餐减去的服务项目数量
                    int reduceCount = 0;
                    // 被套餐减去的服务项目金额
                    decimal reduceAmount = 0.0M;
                    // 需要付费的服务项目数量
                    int payCount = 0;
                    // 代金券金额
                    decimal voucherAmount = 0.0M;
                    // 代金券数量
                    int voucherCount = 0;
                    #region

                    // 处理优惠券
                    for (int packageItenIndex = 0; packageItenIndex < packageItemArray.Length; packageItenIndex++)
                    {
                        WebRef.VSettlementBillPackageItem packageItem = packageItemArray[packageItenIndex];
                        if (packageItem.PackageItemTagDataType == Constant.PackageItemTypes.Voucher)
                        {
                            voucherCount++;
                            voucherAmount += packageItem.PackageItemValue;
                        }
                    }

                    // 处理服务项的抵消
                    for (int serviceItemIndex = 0; serviceItemIndex < serviceItemArray.Length; serviceItemIndex++)
                    {
                        bool isReduce = false;
                        for (int packageItenIndex = 0; packageItenIndex < packageItemArray.Length; packageItenIndex++)
                        {
                            WebRef.VSettlementBillPackageItem packageItem = packageItemArray[packageItenIndex];

                            if (packageItem.PackageItemTagDataType == Constant.PackageItemTypes.ServiceItem)
                            {
                                Guid serviceItemId = new Guid(packageItem.PackageItemTagData);
                                if (serviceItemId == serviceItemArray[serviceItemIndex].ServiceItemId)
                                {
                                    reduceCount++;
                                    reduceAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour * serviceItemArray[serviceItemIndex].Discount;
                                    segmentOriginalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour;
                                    segmentAcutalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour * serviceItemArray[serviceItemIndex].Discount;
                                    isReduce = true;
                                    break;
                                }
                            }
                        }
                        if (!isReduce)
                        {
                            payCount++;
                            segmentOriginalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour;
                            segmentAcutalAmount += serviceItemArray[serviceItemIndex].Price * serviceItemArray[serviceItemIndex].Hour * serviceItemArray[serviceItemIndex].Discount;
                        }
                    }
                    #endregion
                    amount += segmentAcutalAmount;
                    amount -= voucherAmount;
                    amount -= reduceAmount;
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, payCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐项目)", reduceAmount, reduceCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐代金券)", voucherAmount, voucherCount);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, payCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐项目)", reduceAmount, reduceCount);
                        detailBuilder.AppendFormat("-{0:N2}({1}套餐代金券)", voucherAmount, voucherCount);
                    }
                }
                else
                {
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, 0);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, 0);
                    }
                }
                #endregion
            }
            else
            {
                #region 无套餐
                if (serviceItemArray != null)
                {
                    for (int index = 0; index < serviceItemArray.Length; index++)
                    {
                        segmentOriginalAmount += serviceItemArray[index].Price * serviceItemArray[index].Hour;
                        segmentAcutalAmount += serviceItemArray[index].Price * serviceItemArray[index].Hour * serviceItemArray[index].Discount;
                    }
                    amount += segmentAcutalAmount;
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, serviceItemArray.Length);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}({1}服务项目)", segmentAcutalAmount, serviceItemArray.Length);
                    }
                }
                else
                {
                    if (multLineDetail == true)
                    {
                        detailBuilder.Append("服务项目:");
                        detailBuilder.AppendFormat("+{0:N2}(0服务项目)", segmentAcutalAmount);
                        detailBuilder.AppendLine();
                    }
                    else
                    {
                        detailBuilder.AppendFormat("+{0:N2}(0服务项目)", segmentAcutalAmount);
                    }
                }
                #endregion
            }

            segmentOriginalAmount = 0.0M;
            segmentAcutalAmount = 0.0M;
            if (materialArray != null && materialArray.Length > 0)
            {
                for (int index = 0; index < materialArray.Length; index++)
                {
                    segmentOriginalAmount += materialArray[index].Price * materialArray[index].Count;
                    segmentAcutalAmount += materialArray[index].Price * materialArray[index].Count * materialArray[index].Discount;
                }
                amount += segmentAcutalAmount;
                if (multLineDetail)
                {
                    detailBuilder.Append("商品物料:");
                    detailBuilder.AppendFormat("+{0:N2}({1}商品)", segmentAcutalAmount, materialArray.Length);
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}({1}商品)", segmentAcutalAmount, materialArray.Length);
                }
            }
            else
            {
                if (multLineDetail)
                {
                    detailBuilder.Append("商品物料:");
                    detailBuilder.AppendFormat("+{0:N2}(0商品)", segmentAcutalAmount);
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}(0商品)", segmentAcutalAmount);
                }
            }

            decimal discountAmount = 0.0M;
            int discountCount = 0;
            decimal paymentAmount = 0.0M;
            int paymentCount = 0;
            if (payItemArray != null && payItemArray.Length > 0)
            {
                for (int index = 0; index < payItemArray.Length; index++)
                {
                    if (payItemArray[index].Type == Domain.Constant.PayItemTypes.Discount)
                    {
                        discountAmount += payItemArray[index].Amount;
                        discountCount++;
                    }
                    else
                    {
                        paymentAmount += payItemArray[index].Amount;
                        paymentCount++;
                    }
                }
                amount -= discountAmount;
                amount += paymentAmount;
                if (multLineDetail)
                {
                    detailBuilder.Append("其他项目:");
                    detailBuilder.AppendFormat("+{0:N2}({1}付费项)", paymentAmount, paymentCount);
                    detailBuilder.AppendFormat("-{0:N2}({1}优惠项)", discountAmount, discountCount);
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}({1}付费项)", paymentAmount, paymentCount);
                    detailBuilder.AppendFormat("-{0:N2}({1}优惠项)", discountAmount, discountCount);
                }
            }
            else
            {
                if (multLineDetail)
                {
                    detailBuilder.Append("其他项目:");
                    detailBuilder.AppendFormat("+{0:N2}(0付费项)", paymentAmount);
                    detailBuilder.AppendFormat("-{0:N2}(0优惠项)", discountAmount);

                    if (spendBalance > 0)
                    {
                        amount -= spendBalance;
                        detailBuilder.AppendFormat("-{0:N2}(余额)", spendBalance);
                    }
                    detailBuilder.AppendLine();
                }
                else
                {
                    detailBuilder.AppendFormat("+{0:N2}(0付费项)", paymentAmount);
                    detailBuilder.AppendFormat("-{0:N2}(0优惠项)", discountAmount);

                    if (spendBalance > 0)
                    {
                        amount -= spendBalance;
                        detailBuilder.AppendFormat("-{0:N2}(余额)", spendBalance);
                    }
                }
            }
            if (multLineDetail)
            {
                detailBuilder.AppendLine("----------------------------------------");
            }

            if (amount < 0)
            {
                amount = 0;
            }
            detail = detailBuilder.ToString();
            return amount;
        }
    }
}
